﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NUnit.Framework.SyntaxHelpers;

namespace Space_Conquest
{

    enum AITaskType
    {
        MoveToTile,
        GatherResource,
        BuildBuilding,
        CreateUnit,
        AttackUnit,
        Wait
    }

    class AITask
    {

        public AITaskType Task;
        public object[] Parameters;

        public AITask(AITaskType task, params object[] parameters)
        {

            Task = task;
            Parameters = parameters;

        }

    }

    class AI : IMotion
    {

        #region Private Variables

        Player _playerControlling;
        GameEngine _parent;
        Queue<AITask> _tasks;

        #endregion

        #region Properties

        public Player PlayerControlling
        {
            get
            {
                return _playerControlling;
            }
        }

        public GameEngine Parent
        {
            get
            {
                return _parent;
            }
        }

        #endregion

        #region Constructors

        public AI(GameEngine parent, Player playerToControl)
        {

            _parent = parent;
            _playerControlling = playerToControl;
            _tasks = new Queue<AITask>();
            
        }

        #endregion

        #region IMotion Members

        public void Motion()
        {

            if (_tasks.Count > 0)
            {
                // AI has something to do already...
                ParseNextTask();
            }
            else
            {
                // AI needs to figure out something to do...

                if (new Random().Next(0, 100) == 50)
                {
                    Laborer l = GetIdleLaborer();

                    if (l != null)
                    {
                        _tasks.Enqueue(new AITask(AITaskType.MoveToTile, l, GetRandomAdjacentMapPoint(l.MapPoint))); 
						
                    }

                }

            }

        }

        #endregion

        #region Methods

        void ParseNextTask()
        {

            AITask task = _tasks.Peek();

            switch (task.Task)
            {
                case AITaskType.Wait:
                    
                    if ((int)task.Parameters[0] > 0)
                    {
                        task.Parameters[0] = ((int)(task.Parameters[0])) - 1;
                    }
                    else
                    {
                        _tasks.Dequeue();
                    }

                    break;
                case AITaskType.MoveToTile:

                    Unit unitToMove = (Unit)task.Parameters[0];
                    MapPoint pointToMoveTo = (MapPoint)task.Parameters[1];

                    SelectUnit(unitToMove);
                    ClickTile(MouseButtons.Right, pointToMoveTo);

                    _tasks.Dequeue();

                    break;
            }

        }

        #endregion

        #region Player Simulation Methods

        void SelectUnit(Unit unit)
        {
            ClickTile(MouseButtons.Left, unit.MapPoint);
        }

        void ClickTile(MouseButtons button, MapPoint point)
        {
            ClickTile(button, point.X, point.Y);
        }

        void ClickTile(MouseButtons button, int x, int y)
        {
            _playerControlling.MouseDown(button, (x * Globals.TILE_SIZE) + 15, (y * Globals.TILE_SIZE) + 15); 
        }

        #endregion

        #region Player Specific Methods

        private Laborer GetIdleLaborer()
        {

            var idleLaborers =
                from u in _playerControlling.MyUnits
                where
                    u.IsAlive &&
                    u is Laborer &&
                    ((Laborer)u).IsIdle
                select u;

            if (idleLaborers.Count() > 0)
            {
                return (Laborer)idleLaborers.ToArray()[0];
            }
            else
            {
                return null;
            }

        }

        #endregion

        #region Other Helper Methods

        private MapPoint GetRandomAdjacentMapPoint(MapPoint point)
        {
            int random = new Random().Next(0, 4);

            switch (random)
            {

                case 1:
                    return new MapPoint(point.X + 1, point.Y);
                case 2:
                    return new MapPoint(point.X - 1, point.Y);
                case 3:
                    return new MapPoint(point.X, point.Y + 1);
                case 4:
                    return new MapPoint(point.X, point.Y - 1);
                default:
                    throw new Exception("Error finding random direction.");
            }
                
        }

        #endregion

    }

}
